//////////////////////////////////////////////////////////////////////////
//
// GAM203
// Sound Emitter
// SoundEmitter.cpp
// 
// Scott Taylor
// Qantm College
//
//////////////////////////////////////////////////////////////////////////

#include "SoundEmitter.h"

#include "SoundSample.h"

#include "SoundMgr.h"  // Only for VectorTriplet

#include <fmod.h>

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

static const int CHANNEL_INVALID = -1;  // This matches FMOD's return value for 'fail / invalid channel'

SoundEmitter::SoundEmitter(SoundSample* a_pSample)
  : m_channel(CHANNEL_INVALID)  // Begin with no channel
  , m_isPlaying(false)
  , m_destroyOnStop(false)
  , m_pSample(a_pSample)
  , m_errorCode(FMOD_ERR_NONE)
{
}

SoundEmitter::~SoundEmitter()
{
}

//
// Per-frame update
//
void SoundEmitter::Update()
{
  if (m_isPlaying)
  {
    m_isPlaying = !!FSOUND_IsPlaying(m_channel);
    if (!m_isPlaying)
    {
      // Sound has just finished playing; channel is now free
      m_channel = CHANNEL_INVALID;
    }
  }
}

//
// Plays our sample
// Returns true if playing
//
bool SoundEmitter::Play()
{
  if (m_pSample && m_pSample->GetHandle())
  {
    // If we were playing a sound previously, stop it first
    Stop();

    // Begin playing new sound - this will give us a new channel value
    m_channel = FSOUND_PlaySound(FSOUND_FREE, m_pSample->GetHandle());
    if (m_channel != -1)
    {
      // Successfully began playing sound
      m_isPlaying = true;
      return true;
    }
    else
    {
      // Failed to begin playing
      m_errorCode = FSOUND_GetError();
    }
  }
  return false;
}

//
// Plays our sample (looping)
// Returns true if playing
//
bool SoundEmitter::PlayLooping()
{
  if (m_pSample && m_pSample->GetHandle())
  {
    // If we were playing a sound previously, stop it first
    Stop();

    // Begin paused
    m_channel = FSOUND_PlaySoundEx(FSOUND_FREE, m_pSample->GetHandle(), NULL, TRUE);
    if (m_channel != -1)
    {
      // Enable looping
      FSOUND_SetLoopMode(m_channel, FSOUND_LOOP_NORMAL);
      // Unpause
      FSOUND_SetPaused(m_channel, FALSE);

      m_isPlaying = true;
      return true;
    }
    else
    {
      // Failed to begin playing
      m_errorCode = FSOUND_GetError();
    }
  }
  return false;
}

//
// Pauses this emitter's sound
// Returns true if it was playing and is now paused
//
bool SoundEmitter::Pause()
{
  // Only allow pause if this channel is playing
  if (FSOUND_IsPlaying(m_channel))
  {
    return !!FSOUND_SetPaused(m_channel, TRUE);
  }
  return false;
}

//
// Unpauses this emitter's sound
// Returns true if it was paused and is now unpaused
//
bool SoundEmitter::Unpause()
{
  // Only allow unpause if this channel is paused
  if (FSOUND_GetPaused(m_channel))
  {
    return !!FSOUND_SetPaused(m_channel, FALSE);
  }
  return false;
}

//
// Determines whether this emitter's sound is currently paused
//
bool SoundEmitter::IsPaused()
{
  return !!FSOUND_GetPaused(m_channel);
}

//
// Stops this emitter's sound
// Returns true if it was playing / paused and was successfully stopped
//
bool SoundEmitter::Stop()
{
  m_isPlaying = false;
  if (m_channel != CHANNEL_INVALID)
  {
    m_channel = CHANNEL_INVALID;
    return !!FSOUND_StopSound(m_channel);
  }
  return false;
}

//
// Sets this emitter's 3D position
// Returns true if FMOD says it was successful
//
bool SoundEmitter::SetPosition(float a_posX, float a_posY, float a_posZ)
{
  SoundMgr::VectorTriplet posVec;
  posVec.x = a_posX;
  posVec.y = a_posY;
  posVec.z = a_posZ;

  // Don't bother setting velocity (used by doppler only)
  return !!FSOUND_3D_SetAttributes(m_channel, (float*)&posVec, NULL);
}

//
// Sets this emitter's volume (0..1)
// Returns true if FMOD says it was successful
//
bool SoundEmitter::SetVolume(float a_volume)
{
  int volumeAsInt = (int)(a_volume * 255.0f);
  volumeAsInt = max(min(volumeAsInt, 255), 0);  // Clamp within 0..255
  return !!FSOUND_SetVolume(m_channel, volumeAsInt);
}

